﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace System.Windows.Forms
{
    /// <summary>
    /// 表示可控的延迟触发按钮
    /// </summary>
    /// <creator>marc</creator>
    public class DelayButton : Button
    {
        /// <summary>
        /// 表示长按监控器
        /// </summary>
        private Stopwatch _sw;
        /// <summary>
        /// 表示一个后台作业
        /// </summary>
        private BackgroundWorker _worker;

        /// <inheritdoc cref="DelayButton"/>
        public DelayButton()
        {

        }

        /// <summary>
        /// 执行后台作业
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DoWork(object sender, DoWorkEventArgs e)
        {
            for (; ; )
            {
                Thread.Sleep(5);
                if (!this._worker.CancellationPending)
                {
                    ChangeBackground(_sw.ElapsedMilliseconds);
                }
                else
                {
                    break;
                }
            }
        }

        /// <summary>
        /// 延迟多久才触发按钮事件，默认0，单位毫秒
        /// </summary>
        [Browsable(true)]
        [Category("Xejen")]
        [DefaultValue(0)]
        [Description("表示延迟多久才触发按钮事件，默认0，单位毫秒")]
        public int Interval { get; set; } = 0;

        /// <summary>
        /// 表示渐变颜色的上部分，默认为正规绿色
        /// </summary>
        [Browsable(true)]
        [Category("Xejen")]
        [Description("表示渐变颜色的上部分，默认为正规绿色")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color GradientUpColor { get; set; } = Color.Green;

        /// <summary>
        /// 表示渐变颜色的下部分，默认为高亮绿色
        /// </summary>
        [Browsable(true)]
        [Category("Xejen")]
        [Description("表示渐变颜色的下部分，默认为高亮绿色")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color GradientDownColor { get; set; } = Color.LightGreen;

        /// <summary>
        /// 当点击按钮时触发事件，此事件的默认实现已被屏蔽
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClick(EventArgs e) { }

        /// <summary>
        /// 当且仅当鼠标指针在组件上方并按下鼠标时发生
        /// </summary>
        /// <param name="mevent"></param>
        protected override void OnMouseDown(MouseEventArgs mevent)
        {
            this._worker = new BackgroundWorker();
            this._worker.WorkerSupportsCancellation = true;
            this._worker.DoWork += DoWork;
            this._sw = new Stopwatch();
            this._sw.Start();
            this._worker.RunWorkerAsync();

            base.OnMouseDown(mevent);
        }

        /// <summary>
        /// 当且仅当鼠标指针在组件上方并释放鼠标时发生
        /// </summary>
        /// <param name="mevent"></param>
        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            _sw.Stop();
            if (_sw.ElapsedMilliseconds >= this.Interval)
            {
                base.OnClick(new EventArgs());
            }
            base.OnMouseUp(mevent);
            this._worker.CancelAsync();
            this.ResumeBackground();
        }

        /// <summary>
        /// 变更背景色
        /// </summary>
        /// <param name="elapsedMilliseconds">表示逝去的时间</param>
        private void ChangeBackground(long elapsedMilliseconds)
        {
            if (this.Interval <= 0)
            {
                return;
            }

            if (elapsedMilliseconds > this.Interval)
            {
                elapsedMilliseconds = this.Interval;
            }

            var width = this.Width * elapsedMilliseconds / this.Interval;

            Bitmap newGradientBackImg = new Bitmap(this.Width, this.Height);
            LinearGradientBrush brush = new LinearGradientBrush(new PointF(0, 0), new PointF(0, this.Height), GradientUpColor, GradientDownColor);
            Graphics gr = Graphics.FromImage(newGradientBackImg);
            gr.FillRectangle(brush, new RectangleF(0, 0, width, this.Height));
            this.BackgroundImage = newGradientBackImg;
        }

        /// <summary>
        /// 恢复默认的按钮背景
        /// </summary>
        private void ResumeBackground()
        {
            this.BackgroundImage = null;
        }
    }

}
